﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
using System.Collections;
using System.Windows;
using System.Collections.Specialized;
using AGMLite.BaseClass;
using System.Reflection;
using System.Collections.ObjectModel;
using HPAGMRestAPIWrapper;
using System.Windows.Media.Imaging;
using System.Windows.Threading;
using System.Threading;

namespace AGMLite.ViewModelClass
{
    public class ItemViewModel : ViewModelBase
    {
        #region Properties
        public AGMItem Item
        {
            get
            {
                return _item;
            }
            set
            {
                if (value != _item)
                {
                    _item = value;
                    OnPropertyChanged("Item");
                }
            }
        }

        public ObservableCollection<string> EntityTypes
        {
            get
            {
                return _entityTypes;
            }
            set
            {
                if (value != _entityTypes)
                {
                    _entityTypes = value;
                    OnPropertyChanged("EntityTypes");
                }
            }
        }
        public ObservableCollection<string> FilterFieldOperations
        {
            get
            {
                return _filterFieldOperations;
            }
            set
            {
                if (value != _filterFieldOperations)
                {
                    _filterFieldOperations = value;
                    OnPropertyChanged("FilterFieldOperations");
                }
            }
        }
        public Action CloseAction { get; set; }
        #endregion

        #region Private members
        private AGMItem _item;
        private AGMItem _clonedItem;
        private ObservableCollection<string> _filterFieldOperations;
        private ObservableCollection<string> _entityTypes;
        private List<string> _changedFields;

        private RelayCommand<object> saveCommand;
        private RelayCommand<object> cancelCommand;
        private RelayCommand<object> addFilterFieldCommand;
        private RelayCommand<object> deleteFilterFieldCommand;
        private RelayCommand<object> addViewFieldCommand;
        private RelayCommand<object> deleteViewFieldCommand;
        private RelayCommand<object> moveUpViewFieldCommand;
        private RelayCommand<object> moveDownViewFieldCommand;
        #endregion

        public ItemViewModel(AGMItem item)
        {
            EntityTypes = Common.AGMLiteEnum.GetEnumValues(typeof(Common.AGMLiteEnum.EntityType));
            FilterFieldOperations = Common.AGMLiteEnum.GetEnumValues(typeof(Common.AGMLiteEnum.Operation));

            _changedFields = new List<string>();
            _clonedItem = item.DeepCopy();

            Item = item;
            Item.PropertyChanged += PropertyChangedHandler;
        }

        public void OnEntityTypeChanged(Common.AGMLiteEnum.EntityType entitytype)
        {
            Dispatcher.CurrentDispatcher.BeginInvoke(DispatcherPriority.Background, new Action(() =>
              {
                Item.UpdateAllFields();
              }));
        }

        public void PropertyChangedHandler(object sender, PropertyChangedEventArgs e)
        {
            if (!_changedFields.Contains(e.PropertyName))
                _changedFields.Add(e.PropertyName);
        }

        #region Commands
        public System.Windows.Input.ICommand SaveCommand
        {
            get
            {
                if (saveCommand == null)
                {
                    saveCommand = new RelayCommand<object>(x => this.Save(), x => this.CanSave());
                }
                return saveCommand;
            }
        }

        public System.Windows.Input.ICommand CancelCommand
        {
            get
            {
                if (cancelCommand == null)
                {
                    cancelCommand = new RelayCommand<object>(x => this.Cancel(), x => this.CanCancel());
                }
                return cancelCommand;
            }
        }

        public System.Windows.Input.ICommand AddFilterFieldCommand
        {
            get
            {
                if (addFilterFieldCommand == null)
                {
                    addFilterFieldCommand = new RelayCommand<object>(x => this.AddFilterField(), x => this.CanAddFilterField());
                }
                return addFilterFieldCommand;
            }
        }

        public System.Windows.Input.ICommand DeleteFilterFieldCommand
        {
            get
            {
                if (deleteFilterFieldCommand == null)
                {
                    deleteFilterFieldCommand = new RelayCommand<object>(x => this.DeleteFilterField(x), x => this.CanDeleteFilterField(x));
                }
                return deleteFilterFieldCommand;
            }
        }

        public System.Windows.Input.ICommand AddViewFieldCommand
        {
            get
            {
                if (addViewFieldCommand == null)
                {
                    addViewFieldCommand = new RelayCommand<object>(x => this.AddViewField(), x => this.CanAddViewField());
                }
                return addViewFieldCommand;
            }
        }

        public System.Windows.Input.ICommand DeleteViewFieldCommand
        {
            get
            {
                if (deleteViewFieldCommand == null)
                {
                    deleteViewFieldCommand = new RelayCommand<object>(x => this.DeleteViewField(x), x => this.CanDeleteViewField(x));
                }
                return deleteViewFieldCommand;
            }
        }

        public System.Windows.Input.ICommand MoveUpViewFieldCommand
        {
            get
            {
                if (moveUpViewFieldCommand == null)
                {
                    moveUpViewFieldCommand = new RelayCommand<object>(x => this.MoveUpViewField(x), x => this.CanMoveUpViewField(x));
                }
                return moveUpViewFieldCommand;
            }
        }

        public System.Windows.Input.ICommand MoveDownViewFieldCommand
        {
            get
            {
                if (moveDownViewFieldCommand == null)
                {
                    moveDownViewFieldCommand = new RelayCommand<object>(x => this.MoveDownViewField(x), x => this.CanMoveDownViewField(x));
                }
                return moveDownViewFieldCommand;
            }
        }
        #endregion

        #region Implementation
        public void RollBackChanges()
        {
            if (_clonedItem != null)
            {
                foreach (string field in _changedFields)
                {
                    PropertyInfo piCurrent = Item.GetType().GetProperty(field);
                    PropertyInfo piSaved = _clonedItem.GetType().GetProperty(field);
                    piCurrent.SetValue(Item, piSaved.GetValue(_clonedItem, null), null);
                }

                Item.FilterFieldCollection = _clonedItem.FilterFieldCollection;
                Item.ViewFieldCollection = _clonedItem.ViewFieldCollection;
            }
        }        

        private void Save()
        {
            if (Item.FilterFieldCollection.Count == 0)
            {
                MessageBox.Show("Please add some filter fields for the item first.", "No Fitler Fields", MessageBoxButton.OK, MessageBoxImage.Warning);
            }
            else
            {
                bool isCanSave = false;
                foreach (AGMLiteEntityFilterField ff in Item.FilterFieldCollection)
                {
                    if (string.IsNullOrEmpty(ff.Field.Name))
                    {
                        MessageBox.Show("You have added a filter field, but the field name is empty.", "No Fitler Field Name", MessageBoxButton.OK, MessageBoxImage.Warning);
                        isCanSave = false;
                        break;
                    }
                    else
                    {
                        isCanSave = true;
                    }
                }

                foreach (AGMLiteEntityViewField vf in Item.ViewFieldCollection)
                {
                    if (string.IsNullOrEmpty(vf.Field.Name))
                    {
                        MessageBox.Show("You have added a view field, but the field name is empty.", "No View Field Name", MessageBoxButton.OK, MessageBoxImage.Warning);
                        isCanSave = false;
                        break;
                    }
                    else
                    {
                        isCanSave = true;
                    }
                }

                if (isCanSave)
                {
                    MessageBoxResult msgBoxResult = MessageBox.Show("Are you sure to save the item?", "Save Item", MessageBoxButton.YesNo, MessageBoxImage.Asterisk);
                    if (msgBoxResult == MessageBoxResult.Yes)
                    {
                        if (string.IsNullOrEmpty(Item.GUID))
                            Item.GUID = Guid.NewGuid().ToString();
                        Item.Save(false);
                        Item.IsRequireSync = true;
                        Item.LiteEntityCollection.Clear();
                        Item.DeleteCacheFile();
                        CloseAction();
                    }
                }
            }
        }

        private void Cancel()
        {
            RollBackChanges();
            Item.IsRequireSync = false;
            CloseAction();
        }

        private bool CanSave()
        {
            return string.IsNullOrEmpty(Item.Error);
        }

        private bool CanCancel()
        {
            return true;
        }

        private void AddFilterField()
        {
            string fieldtype = Common.AGMLiteEnum.GetEntityTypeFromEnum(Item.EntityType);
            List<string> availableFieldTypes = new List<string>();
            availableFieldTypes.Add(fieldtype);
            if (Item.EntityType == Common.AGMLiteEnum.EntityType.Requirement || Item.EntityType == Common.AGMLiteEnum.EntityType.Defect)
                availableFieldTypes.Add("release-backlog-item");

            AGMLiteEntityFilterField newFilterField = new AGMLiteEntityFilterField()
            {
                AvailableFieldTypes = availableFieldTypes,
                AvailableFieldsPool = Item.Project.EntityFields,
            };                        
            Item.FilterFieldCollection.Add(newFilterField);
            UpdateEntityTypeEditableProperty();
        }

        private void AddViewField()
        {
            string fieldtype = Common.AGMLiteEnum.GetEntityTypeFromEnum(Item.EntityType);
            List<string> availableFieldTypes = new List<string>();
            availableFieldTypes.Add(fieldtype);
            if (Item.EntityType == Common.AGMLiteEnum.EntityType.Requirement || Item.EntityType == Common.AGMLiteEnum.EntityType.Defect)
                availableFieldTypes.Add("release-backlog-item");

            AGMLiteEntityViewField newViewField = new AGMLiteEntityViewField()
            {
                AvailableFieldTypes = availableFieldTypes,
                AvailableFieldsPool = Item.Project.EntityFields,
                Order = Item.ViewFieldCollection.Count,
            };
            Item.ViewFieldCollection.Add(newViewField);
            UpdateEntityTypeEditableProperty();
        }

        private void DeleteFilterField(object obj)
        {
            if (obj != null)
            {
                AGMLiteEntityFilterField selectedFilterField = (AGMLiteEntityFilterField)obj;

                MessageBoxResult result = MessageBox.Show("Are you sure you want to delete the filter field?", "Confirm", MessageBoxButton.YesNo, MessageBoxImage.Question);
                if (result == MessageBoxResult.Yes)
                {
                    Item.FilterFieldCollection.Remove(selectedFilterField);
                    UpdateEntityTypeEditableProperty();
                }
            }
        }

        private void DeleteViewField(object obj)
        {
            if (obj != null)
            {
                AGMLiteEntityViewField selectedViewField = (AGMLiteEntityViewField)obj;

                MessageBoxResult result = MessageBox.Show("Are you sure you want to delete the View field?", "Confirm", MessageBoxButton.YesNo, MessageBoxImage.Question);
                if (result == MessageBoxResult.Yes)
                {
                    Item.ViewFieldCollection.Remove(selectedViewField);
                    UpdateEntityTypeEditableProperty();
                    UpdateOrders();
                }
            }
        }

        private void MoveUpViewField(object obj)
        {
            if (obj != null)
            {
                AGMLiteEntityViewField selectedViewField = (AGMLiteEntityViewField)obj;
                int oldOrder = selectedViewField.Order;
                int newOrder = selectedViewField.Order - 1;
                (Item.ViewFieldCollection.Where(o => o.Order == newOrder).Single() as AGMLiteEntityViewField).Order = oldOrder;
                selectedViewField.Order = newOrder;
                Item.ViewFieldCollection.Sort(o => o.Order);
            }
        }

        private void MoveDownViewField(object obj)
        {
            if (obj != null)
            {
                AGMLiteEntityViewField selectedViewField = (AGMLiteEntityViewField)obj;
                int oldOrder = selectedViewField.Order;
                int newOrder = selectedViewField.Order + 1;
                (Item.ViewFieldCollection.Where(o => o.Order == newOrder).Single() as AGMLiteEntityViewField).Order = oldOrder;
                selectedViewField.Order = newOrder;
                Item.ViewFieldCollection.Sort(o => o.Order);
            }
        }

        private bool CanAddFilterField()
        {
            return true;
        }        

        private bool CanDeleteFilterField(object obj)
        {
            if (obj == null)
                return false;

            return true;
        }        

        private bool CanAddSortField()
        {
            return true;
        }        

        private bool CanDeleteSortField(object obj)
        {
            if (obj == null)
                return false;

            return true;
        }        

        private bool CanAddViewField()
        {
            return true;
        }       

        private bool CanDeleteViewField(object obj)
        {
            if (obj == null)
                return false;

            return true;
        }

        private bool CanMoveUpViewField(object obj)
        {
            if (obj == null)
                return false;

            AGMLiteEntityViewField viewField = obj as AGMLiteEntityViewField;
            if (viewField.Order == 0)
                return false;

            return true;
        }

        private bool CanMoveDownViewField(object obj)
        {
            if (obj == null)
                return false;

            AGMLiteEntityViewField viewField = obj as AGMLiteEntityViewField;
            if (viewField.Order == Item.ViewFieldCollection.Count - 1)
                return false;

            return true;
        }

        private void UpdateOrders()
        {
            int index = 0;
            foreach (AGMLiteEntityViewField vf in Item.ViewFieldCollection.OrderBy(o => o.Order))
            {
                vf.Order = index;
                index++;
            }
        }

        private void UpdateEntityTypeEditableProperty()
        {
            if (Item.FilterFieldCollection.Count > 0  || Item.ViewFieldCollection.Count > 0)
                Item.CanEditEntityType = false;
            else
                Item.CanEditEntityType = true;
        }
        #endregion
    }
}
